import type { Packet } from './packet'
import type { Connect } from './index'
import { EventEmitter } from 'events'

export abstract class PacketHandler extends EventEmitter {
  constructor(connect: Connect) {
    super()
    this.connect = connect
  }

  readonly connect: Connect

  on<K extends keyof HandlerEvents>(event: K, listener: HandlerEvents[K]) {
    return super.on(event, listener)
  }

  off<K extends keyof HandlerEvents>(event: K, listener: HandlerEvents[K]) {
    return super.off(event, listener)
  }

  emit<K extends keyof HandlerEvents>(event: K, ...args: Parameters<HandlerEvents[K]>) {
    return super.emit(event, ...args)
  }

  complete() {
    this.emit('complete')
  }

  abstract handler(packet: Packet): void
}

interface HandlerEvents {
  complete: () => void
}

export class PacketStepHandler extends PacketHandler {
  constructor(connect: Connect) {
    super(connect)
  }

  protected readonly steps: StepType[] = []

  protected _index = 0

  step(cp: StepType) {
    this.steps.push(cp)
    return this
  }

  next(index?: number) {
    this._index = index !== void 0 ? index : ++this._index

    if (this._index > this.steps.length - 1) {
      this.complete()
    }
  }

  handler(packet: Packet): void {
    const step = this.steps[this._index]
    const next = () => this.next()
    if (step) {
      step.call(this, packet, next, this)
    }
  }

  get index() {
    return this._index
  }
}

export type StepType = (
  this: PacketStepHandler,
  packet: Packet,
  next: () => void,
  ctx: PacketStepHandler
) => void
